import numpy as np
import pandas as pd

all_point_name = ['L5HP','L5HA','L5FP','L5FA','S1HP', 'S1HA', 'S1FP', 'S1FA']
all_point_name_x = ['L5HP_x','L5HA_x','L5FP_x','L5FA_x','S1HP_x', 'S1HA_x', 'S1FP_x', 'S1FA_x']
all_point_name_y = ['L5HP_y','L5HA_y','L5FP_y','L5FA_y','S1HP_y', 'S1HA_y', 'S1FP_y', 'S1FA_y']
def get_4point_calculate(label_csv_dir, pred_csv_dir,):
    def calculate(points):
        Calculate_Result = {}
        
        def vector_norm(data, axis=None, out=None):
            data = np.array(data, dtype=np.float64, copy=True)
            if out is None:
                if data.ndim == 1:
                    return np.sqrt(np.dot(data, data))
                data *= data
                out = np.atleast_1d(np.sum(data, axis=axis))
                np.sqrt(out, out)
                return out
            else:
                data *= data
                np.sum(data, axis=axis, out=out)
                np.sqrt(out, out)
        
        def angle_between_vectors(v0, v1, directed=True, axis=0):
            v0 = np.array(v0, dtype=np.float64, copy=False)
            v1 = np.array(v1, dtype=np.float64, copy=False)
            dot = np.sum(v0 * v1, axis=axis)
            dot /= vector_norm(v0, axis=axis) * vector_norm(v1, axis=axis)
            return np.arccos(dot if directed else np.fabs(dot))
        
        def degree_four_points(v0_s, v0_e, v1_s, v1_e):
            """
            计算由四个点组成的两个向量间的夹角，用于计算侧弯角等。
            三个点的也可构造成四个点调用该函数。
            :param v0_s:第一个向量的起始点
            :param v0_e:第一个向量的终止点
            :param v1_s:第二个向量的起始点
            :param v1_e:第二个向量的终止点
            """
            v0 = np.asarray(v0_e) - np.asarray(v0_s)
            v1 = np.asarray(v1_e) - np.asarray(v1_s)
            return np.rad2deg(angle_between_vectors(v0, v1))
        
        def min_angle_between_vector_and_horizontal_line(vs, ve):
            """
            计算向量与水平向量的最小夹角
            """
            v = np.asarray(ve) - np.asarray(vs)
            vh = np.asarray([ve[0], vs[1]]) - np.asarray(vs)
            return np.rad2deg(angle_between_vectors(v, vh))
        
        def min_angle_between_vector_and_vertical_line(vs, ve):
            """
                计算向量与竖直向量的最小夹角
                """
            v = np.asarray(ve) - np.asarray(vs)
            vt = np.asarray([vs[0], ve[1]]) - np.asarray(vs)
            return np.rad2deg(angle_between_vectors(v, vt))
        
        def sacrum_tilt():
            """
            骶骨倾斜角
            """
            vs = points["S1HP"][:2]
            ve = points["S1HA"][:2]
            Calculate_Result["SHA"] = min_angle_between_vector_and_horizontal_line(vs, ve)
            vs = points["S1FP"][:2]
            ve = points["S1HP"][:2]
            Calculate_Result["SIA"] = min_angle_between_vector_and_vertical_line(vs, ve)
        
        def lumbosacral_angle():
            """
            腰骶夹角
            """
            v0_s = points["S1HA"][:2]
            v0_e = points["S1FA"][:2]
            v1_s = points["L5FA"][:2]
            v1_e = points["L5HA"][:2]
            Calculate_Result["LSLA"] = degree_four_points(v0_s, v0_e, v1_s, v1_e)
        
        def intervertebral_angle():
            ## 椎间盘角
            v0_s = points['L5' + "FP"][:2]
            v0_e = points['L5' + "FA"][:2]
            v1_s = points['S1' + "HP"][:2]
            v1_e = points['S1' + "HA"][:2]
            Calculate_Result['LSA'] = degree_four_points(v0_s, v0_e, v1_s, v1_e)
        
        sacrum_tilt()
        lumbosacral_angle()
        intervertebral_angle()
        return Calculate_Result
    
    label_csv = pd.read_csv(label_csv_dir)
    pred_csv = pd.read_csv(pred_csv_dir)
    merge_csv = pd.merge(label_csv,pred_csv,on='image_path',how='inner')
    merge_csv.to_csv('label_file/lumbar/merge.csv',index=False)
    save_pred = pd.DataFrame(columns=['name','LSLA', 'LSA', 'SIA', 'SHA'])
    save_label = pd.DataFrame(columns=['name','LSLA', 'LSA', 'SIA', 'SHA'])
    l2_loss_list = []
    for index in range(len(merge_csv)):
        try:
            name = merge_csv.iloc[index].loc['image_path']
            label_point = [merge_csv.iloc[index].loc[p] for p in all_point_name_x]
            label_point = [[int(p.split(',')[0].replace("[[",'')),int(p.split(',')[1].replace("]]",''))] for p in label_point]
            
            pred_point = [merge_csv.iloc[index].loc[p] for p in all_point_name_y]
            pred_point = [[int(float(p.split(',')[0].replace("(",''))),int(float(p.split(',')[1].replace(")",'')))] for p in pred_point]


            l2_loss = [(((label_point[index][0] - pred_point[index][0])**2 + (label_point[index][0] - pred_point[index][0])**2)**0.5) *0.139 for index in range(len(pred_point))]
            if np.max(l2_loss) > 100:
                continue
            l2_loss_list += l2_loss
            label_point = dict(zip(all_point_name, label_point))
            pred_point = dict(zip(all_point_name,pred_point))
            calculate_pred = calculate(pred_point)
            calculate_label = calculate(label_point)
            calculate_pred['name'] = name
            calculate_label['name'] = name
            save_pred = save_pred.append(pd.DataFrame(calculate_pred,index=[0]))
            save_label = save_label.append(pd.DataFrame(calculate_label,index=[0]))
        except Exception as e:
            pass
            # print('*'*100,e)
    print([np.sum([int(p<i) for p in l2_loss_list])/len(l2_loss_list) for i in [0.5+i*0.5 for i in range(10)]])
    print(np.sum([int(p<2) for p in l2_loss_list])/len(l2_loss_list),np.mean(l2_loss_list),np.median(l2_loss_list),)
    save_label = save_label[['name','LSLA', 'LSA', 'SIA', 'SHA']]
    save_pred = save_pred[['name','LSLA', 'LSA', 'SIA', 'SHA']]
    # save_label.to_csv('label_file/lumbar/label_calculate_0602.csv',index=False)
    # save_pred.to_csv('label_file/lumbar/pred_calculate_0602.csv',index=False)
    


def merge_data():
    pred_0 = pd.read_csv('pred_result/pred_calculate_0.csv')
    pred_1 = pd.read_csv('pred_result/pred_calculate_1.csv').iloc[:150]
    label_0 = pd.read_csv('pred_result/label_calculate_0.csv')
    label_1 = pd.read_csv('pred_result/label_calculate_1.csv').iloc[:150]
    pred_2 = pd.concat([pred_0,pred_1],axis=0)
    pred_2 = pred_2.sample(frac=1.0)
    pred_2 = pred_2[['name','LSLA', 'LSA', 'SIA', 'SHA']]
    pred_2.to_csv('label/lumbar/pred_calculate_0602.csv')
    label_2 = pd.concat([label_0,label_1],axis=0)
    label_2 = label_2.sample(frac=1.0)
    label_2 = label_2[['name','LSLA', 'LSA', 'SIA', 'SHA']]
    label_2.to_csv('label/lumbar/label_calculate_0602.csv')
if __name__ == '__main__':
    # get_4point_calculate(label_csv_dir='/home/lmy/jizhu/jizhu/heatmap_code/label_file/0510/merge_train_0522.csv',pred_csv_dir='cewei_4points_1.csv')
    # get_4point_calculate(label_csv_dir='/home/lmy/jizhu/jizhu/heatmap_code/label_file/0510/merge_val_0522.csv',pred_csv_dir='cewei_4points.csv')
    get_4point_calculate(label_csv_dir='label_file/lumbar/cewei_transform.csv',pred_csv_dir='label_file/lumbar/L5S10525.csv')
    # merge_data()